package com.zhi.syc.data_applist.util;

import android.app.ActivityManager;
import android.app.usage.StorageStatsManager;
import android.content.Context;
import android.os.Build;
import android.os.Environment;
import android.os.StatFs;
import android.os.storage.StorageManager;
import android.os.storage.StorageVolume;

import com.zhi.syc.data_applist.logger.ASLogger;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.IllegalFormatException;
import java.util.List;
import java.util.UUID;

public class ASStoreUtil {

    public static final String KEY_TOTAL = "total";
    public static final String KEY_AVAILABLE = "available";
    public static final String KEY_USED = "used";

    public static String getTotalInternalStoreSize(Context context) {
        String sizeStr = "0";
        try {
            JSONObject jsonObject = getInternalStoreSize(context);
            sizeStr = jsonObject.getString(KEY_TOTAL);
        } catch (JSONException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sizeStr;
    }

    public static String getAvailaInternalStoreSize(Context context) {
        String sizeStr = "0";
        try {
            JSONObject jsonObject = getInternalStoreSize(context);
            sizeStr = jsonObject.getString(KEY_AVAILABLE);
        } catch (JSONException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sizeStr;
    }

    public static JSONObject getInternalStoreSize(Context context) {
        //5.0 查外置存储
        float unit = 1024;
        int version = Build.VERSION.SDK_INT;
        if (version < Build.VERSION_CODES.M) {//小于6.0
            StorageManager storageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
            JSONObject storeObj = new JSONObject();
            try {
                Method getVolumeList = StorageManager.class.getDeclaredMethod("getVolumeList");
                StorageVolume[] volumeList = (StorageVolume[]) getVolumeList.invoke(storageManager);
                long totalSize = 0, availableSize = 0;
                if (volumeList != null) {
                    Method getPathFile = null;
                    for (StorageVolume volume : volumeList) {
                        if (getPathFile == null) {
                            getPathFile = volume.getClass().getDeclaredMethod("getPathFile");
                        }
                        File file = (File) getPathFile.invoke(volume);
                        if (file != null) {
                            totalSize += file.getTotalSpace();
                            availableSize += file.getUsableSpace();
                        }
                    }
                }

                ASLogger.d("before-getInternalStoreSize", "totalSize = " + totalSize + " ,availableSize = " + availableSize);

                String totalStore = getUnit(totalSize, unit);
                String usedStore = "0";
                String availableStore = getUnit(availableSize, unit);
                ASLogger.d("after-getInternalStoreSize", "totalSize = " + totalStore + " ,availableSize = " + availableStore);

                storeObj.put(KEY_TOTAL, totalStore);
                storeObj.put(KEY_AVAILABLE, availableStore);
                storeObj.put(KEY_USED, usedStore);

                volumeList = null;
                return storeObj;

            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (JSONException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return storeObj;

        } else {
            JSONObject storeObj = new JSONObject();
            try {
                StorageManager storageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
                Method getVolumes = StorageManager.class.getDeclaredMethod("getVolumes");//6.0
                List<Object> getVolumeInfo = (List<Object>) getVolumes.invoke(storageManager);
                long total = 0L, used = 0L;
                for (Object obj : getVolumeInfo) {

                    Field getType = obj.getClass().getField("type");
                    int type = getType.getInt(obj);

                    //ASLogger.d("getInternalStoreSize", "type: " + type);
                    if (type == 1) {//TYPE_PRIVATE
                        long totalSize = 0L;

                        //获取内置内存总大小
                        if (version >= Build.VERSION_CODES.O) {//8.0
                            unit = 1000;
                            Method getFsUuid = obj.getClass().getDeclaredMethod("getFsUuid");
                            String fsUuid = (String) getFsUuid.invoke(obj);
                            totalSize = getTotalSize(context, fsUuid);//8.0 以后使用
                        } else if (version >= Build.VERSION_CODES.N_MR1) {//7.1.1
                            Method getPrimaryStorageSize = StorageManager.class.getMethod("getPrimaryStorageSize");//5.0 6.0 7.0没有
                            //totalSize = (long) getPrimaryStorageSize.invoke(storageManager);
                        }
                        long systemSize = 0L;

                        Method isMountedReadable = obj.getClass().getDeclaredMethod("isMountedReadable");
                        boolean readable = (boolean) isMountedReadable.invoke(obj);
                        if (readable) {
                            Method file = obj.getClass().getDeclaredMethod("getPath");
                            File f = (File) file.invoke(obj);
                            if (f != null) {
                                if (totalSize == 0) {
                                    totalSize = f.getTotalSpace();
                                }
                                systemSize = totalSize - f.getTotalSpace();
                                used += totalSize - f.getFreeSpace();
                                total += totalSize;
                            }
                        }
                        //ASLogger.d("getInternalStoreSize", "设备内存大小：" + getUnit(totalSize, unit) + "\n系统大小：" + getUnit(systemSize, unit));
                        //ASLogger.d("getInternalStoreSize", "totalSize = " + getUnit(totalSize, unit) + " ,used(with system) = " + getUnit(used, unit) + " ,free = " + getUnit(totalSize - used, unit));

                    } else if (type == 0) {//TYPE_PUBLIC
                        //外置存储
                        Method isMountedReadable = obj.getClass().getDeclaredMethod("isMountedReadable");
                        boolean readable = (boolean) isMountedReadable.invoke(obj);
                        if (readable) {
                            Method file = obj.getClass().getDeclaredMethod("getPath");
                            File f = (File) file.invoke(obj);
                            if (f != null) {
                                used += f.getTotalSpace() - f.getFreeSpace();
                                total += f.getTotalSpace();
                            }
                        }
                    } else if (type == 2) {//TYPE_EMULATED

                    }
                }

                ASLogger.d("before-getInternalStoreSize", "totalSize = " + total + " ,used(with system) = " + used);

                String totalStore = getUnit(total, unit);
                String usedStore = getUnit(used, unit);
                String availableStore = getUnit((total - used), unit);
                ASLogger.d("getInternalStoreSize", "total = " + totalStore + ",  used(with system) = " + usedStore + ",  available = " + availableStore);

                storeObj.put(KEY_TOTAL, totalStore);
                storeObj.put(KEY_AVAILABLE, availableStore);
                storeObj.put(KEY_USED, usedStore);

                getVolumeInfo = null;
                return storeObj;

            } catch (SecurityException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (JSONException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return storeObj;
        }
    }

    public static long getTotalSize(Context paramContext, String fsUuid) {
        try {
            UUID id;
            StorageStatsManager stats = null;
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
                if (fsUuid == null) {
                    id = StorageManager.UUID_DEFAULT;
                } else {
                    id = UUID.fromString(fsUuid);
                }
                stats = (StorageStatsManager) paramContext.getSystemService(Context.STORAGE_STATS_SERVICE);
                return stats.getTotalBytes(id);
            }
        } catch (NoSuchFieldError | NoClassDefFoundError | NullPointerException | IOException e) {
            e.printStackTrace();
        }
        return -1;
    }

    private static String getUnit(float size, float unit) {
        //8534761472 1024
        String result = "";
        try {
            String[] units = {"B", "KB", "MB", "GB", "TB"};
            int index = 0;
            while (size > unit && index < 4) {
                size = size / unit;
                index++;
            }

            ASLogger.d("before-getUnit", "size = " + size + " ,index = " + index);
            BigDecimal resultDec = new BigDecimal(size);
            resultDec = resultDec.setScale(2, BigDecimal.ROUND_HALF_UP);
            result = resultDec.toPlainString() + units[index];

            ASLogger.d("after-getUnit", "result = " + result + " ,index = " + units[index]);

        } catch (IllegalFormatException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return result;
    }


    public static String getRamCanUse(Context paramContext) {
        try {
            ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
            ((ActivityManager) paramContext.getSystemService(Context.ACTIVITY_SERVICE)).getMemoryInfo(memoryInfo);
            return getUnit(memoryInfo.availMem, 1024);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "0";
    }

    public static String getRamDidUsed(Context paramContext) {
        try {
            long didUsed = 0;
            ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
            ((ActivityManager) paramContext.getSystemService(Context.ACTIVITY_SERVICE)).getMemoryInfo(memoryInfo);
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
                didUsed = (memoryInfo.totalMem - memoryInfo.availMem);
            }
            return getUnit(didUsed, 1024);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "0";
    }

    public static String getRamTotal(Context paramContext) {
        try {
            ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
            ((ActivityManager) paramContext.getSystemService(Context.ACTIVITY_SERVICE)).getMemoryInfo(memoryInfo);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                return getUnit(memoryInfo.totalMem, 1024);
            }
            return "0";

        } catch (Exception e) {
            e.printStackTrace();
        }
        return "0";
    }

    public static String getCashCanUse(Context paramContext) {
        try {
            File file = Environment.getDataDirectory();
            StatFs statFs = new StatFs(file.getPath());
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
                return getUnit(statFs.getAvailableBlocksLong() * statFs.getBlockSizeLong(), 1024);
            } else {
                return getUnit(statFs.getAvailableBlocks() * statFs.getBlockSize(), 1024);
            }

        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return "0";
    }

    public static String getCashDidUsed(Context paramContext) {
        try {
            File file = Environment.getDataDirectory();
            StatFs statFs = new StatFs(file.getPath());
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
                long total = (statFs.getBlockCountLong() * statFs.getBlockSizeLong());
                long avail = (statFs.getAvailableBlocksLong() * statFs.getBlockSizeLong());
                long didUsed = (total - avail);
                return getUnit(didUsed, 1024);
            } else {
                long total = (statFs.getBlockCount() * statFs.getBlockSize());
                long avail = (statFs.getAvailableBlocks() * statFs.getBlockSize());
                long didUsed = (total - avail);
                return getUnit(didUsed, 1024);
            }

        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return "0";
    }

    public static String getCashTotal(Context paramContext) {
        try {
            File file = Environment.getDataDirectory();
            StatFs statFs = new StatFs(file.getPath());
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
                return getUnit(statFs.getBlockCountLong() * statFs.getBlockSizeLong(), 1024);
            } else {
                return getUnit(statFs.getBlockCount() * statFs.getBlockSize(), 1024);
            }

        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return "0";
    }

    public static String getContainSD() {
        if (Environment.getExternalStorageState().equals("mounted")) {
            return "YES";
        }
        return "NO";
    }

    public static String getExtraSD(Context paramContext, int paramInt) {
        try {
//            String esd = null;
//            StorageManager storageManager = (StorageManager) paramContext.getSystemService(Context.STORAGE_SERVICE);
//            Method method = StorageManager.class.getDeclaredMethod("getVolumePaths");
//            method.setAccessible(true);

//            Object result = method.invoke(storageManager);
//            if (result != null && result instanceof String[]) {
//                String[] arrayOfString = (String[]) result;
//                if (paramInt != 0) {
//                    if (paramInt == 1) {
//                        esd = ((arrayOfString.length > 1) ? arrayOfString[paramInt] : "");
//                    }
//                } else {
//                    esd = arrayOfString[paramInt];
//                }
//            }

//            String containSDFlga = getContainSD();
//            boolean containSD = ("YES".equalsIgnoreCase(containSDFlga));
//
//            boolean hadExtra = (!containSD || TextUtils.isEmpty(esd) || esd == null);
//            return (hadExtra ? "NO" : "YES");

            boolean hadExt = false;
            StorageManager storageManager = (StorageManager) paramContext.getSystemService(Context.STORAGE_SERVICE);
            Method method_volumeList = StorageManager.class.getMethod("getVolumeList");
            method_volumeList.setAccessible(true);
            Object[] volumeList = (Object[]) method_volumeList.invoke(storageManager);
            if (volumeList != null) {
                for (int i = 0; i < volumeList.length; i++) {
                    try {
                        String path = (String) (volumeList[i].getClass().getMethod("getPath").invoke(volumeList[i]));
                        boolean isRemovable = (boolean) (volumeList[i].getClass().getMethod("isRemovable").invoke(volumeList[i]));
                        if (!hadExt && isRemovable) {
                            hadExt = true;
                        }
                        ASLogger.d("getExtraSD", "path: " + path + "  isRemovable:" + isRemovable);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    } catch (InvocationTargetException e) {
                        e.printStackTrace();
                    } catch (NoSuchMethodException e) {
                        e.printStackTrace();
                    }
                }
            }
            volumeList = null;

            return (hadExt ? "YES" : "NO");

        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "NO";
    }

    public static String getSDCardTotal(Context paramContext) {
        try {
            if (Environment.getExternalStorageState().equalsIgnoreCase("mounted")) {
                File file = Environment.getExternalStorageDirectory();
                StatFs statFs = new StatFs(file.getPath());
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
                    long l = statFs.getBlockSizeLong();
                    return getUnit(statFs.getBlockCountLong() * l, 1024);
                } else {
                    long l = statFs.getBlockSize();
                    return getUnit(statFs.getBlockCount() * l, 1024);
                    //return Formatter.formatFileSize(paramContext, statFs.getBlockCount() * l);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "0GB";
    }
}
